<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------

/**
 * ThinkPHP Action控制器基类 精简模式
 * @category   Think
 * @package  Think
 * @subpackage  Core
 * @author   liu21st <liu21st@gmail.com>
 */
abstract class Action
{

    // 当前Action名称
    private $name = '';
    protected $tVar = array(); // 模板输出变量

    /**
     * 架构函数 取得模板对象实例
     * @access public
     */
    public function __construct()
    {
        tag('action_begin');
        //控制器初始化
        if (method_exists($this, '_initialize'))
            $this->_initialize();
    }

    /**
     * 获取当前Action名称
     * @access protected
     */
    protected function getActionName()
    {
        if (empty($this->name)) {
            // 获取Action名称
            $this->name = substr(get_class($this), 0, -6);
        }
        return $this->name;
    }

    /**
     * 是否AJAX请求
     * @access protected
     * @return bool
     */
    protected function isAjax()
    {
        if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
            if ('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']))
                return true;
        }
        if (!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')]))
            // 判断Ajax方式提交
            return true;
        return false;
    }

    /**
     * 模板变量赋值
     * @access public
     * @param mixed $name
     * @param mixed $value
     */
    public function assign($name, $value = '')
    {
        if (is_array($name)) {
            $this->tVar = array_merge($this->tVar, $name);
        } elseif (is_object($name)) {
            foreach ($name as $key => $val)
                $this->tVar[$key] = $val;
        } else {
            $this->tVar[$name] = $value;
        }
    }

    public function __set($name, $value)
    {
        $this->assign($name, $value);
    }

    /**
     * 取得模板变量的值
     * @access public
     * @param string $name
     * @return mixed
     */
    public function get($name)
    {
        if (isset($this->tVar[$name]))
            return $this->tVar[$name];
        else
            return false;
    }

    /**
     * 魔术方法 有不存在的操作的时候执行
     * @access public
     * @param string $method 方法名
     * @param array $args 参数
     * @return mixed
     */
    public function __call($method, $args)
    {
        if (0 === strcasecmp($method, ACTION_NAME)) {
            if (method_exists($this, '_empty')) {
                // 如果定义了_empty操作 则调用
                $this->_empty($method, $args);
            } elseif (file_exists_case(C('TEMPLATE_NAME'))) {
                // 检查是否存在默认模版 如果有直接输出模版
                $this->display();
            } else {
                // 抛出异常
                throw_exception(L('_ERROR_ACTION_') . ACTION_NAME);
            }
        } else {
            switch (strtolower($method)) {
                // 判断提交方式
                case 'ispost':
                case 'isget':
                case 'ishead':
                case 'isdelete':
                case 'isput':
                    return strtolower($_SERVER['REQUEST_METHOD']) == strtolower(substr($method, 2));
                // 获取变量 支持过滤和默认值 调用方式 $this->_post($key,$filter,$default);
                case '_get':
                    $input =& $_GET;
                    break;
                case '_post':
                    $input =& $_POST;
                    break;
                case '_put':
                    parse_str(file_get_contents('php://input'), $input);
                    break;
                case '_request':
                    $input =& $_REQUEST;
                    break;
                case '_session':
                    $input =& $_SESSION;
                    break;
                case '_cookie':
                    $input =& $_COOKIE;
                    break;
                case '_server':
                    $input =& $_SERVER;
                    break;
                case '_globals':
                    $input =& $GLOBALS;
                    break;
                default:
                    throw_exception(__CLASS__ . ':' . $method . L('_METHOD_NOT_EXIST_'));
            }
            if (isset($input[$args[0]])) { // 取值操作
                $data = $input[$args[0]];
                $filters = isset($args[1]) ? $args[1] : C('DEFAULT_FILTER');
                if ($filters) {// 2012/3/23 增加多方法过滤支持
                    $filters = explode(',', $filters);
                    foreach ($filters as $filter) {
                        if (function_exists($filter)) {
                            $data = is_array($data) ? array_map($filter, $data) : $filter($data); // 参数过滤
                        }
                    }
                }
            } else { // 变量默认值
                $data = isset($args[2]) ? $args[2] : NULL;
            }
            return $data;
        }
    }

    /**
     * 操作错误跳转的快捷方法
     * @access protected
     * @param string $message 错误信息
     * @param string $jumpUrl 页面跳转地址
     * @param Boolean $ajax 是否为Ajax方式
     * @return void
     */
    protected function error($message, $jumpUrl = '', $ajax = false)
    {
        $this->dispatchJump($message, 0, $jumpUrl, $ajax);
    }

    /**
     * 操作成功跳转的快捷方法
     * @access protected
     * @param string $message 提示信息
     * @param string $jumpUrl 页面跳转地址
     * @param Boolean $ajax 是否为Ajax方式
     * @return void
     */
    protected function success($message, $jumpUrl = '', $ajax = false)
    {
        $this->dispatchJump($message, 1, $jumpUrl, $ajax);
    }

    /**
     * Ajax方式返回数据到客户端
     * @access protected
     * @param mixed $data 要返回的数据
     * @param String $info 提示信息
     * @param boolean $status 返回状态
     * @param String $status ajax返回类型 JSON XML
     * @return void
     */
    protected function ajaxReturn($data, $info = '', $status = 1, $type = '')
    {
        $result = array();
        $result['status'] = $status;
        $result['info'] = $info;
        $result['Data'] = $data;
        //扩展ajax返回数据, 在Action中定义function ajaxAssign(&$result){} 方法 扩展ajax返回数据。
        if (method_exists($this, "ajaxAssign"))
            $this->ajaxAssign($result);
        if (empty($type)) $type = C('DEFAULT_AJAX_RETURN');
        if (strtoupper($type) == 'JSON') {
            // 返回JSON数据格式到客户端 包含状态信息
            header("Content-Type:text/html; charset=utf-8");
            exit(json_encode($result));
        } elseif (strtoupper($type) == 'XML') {
            // 返回xml格式数据
            header("Content-Type:text/xml; charset=utf-8");
            exit(xml_encode($result));
        }
    }

    /**
     * Action跳转(URL重定向） 支持指定模块和延时跳转
     * @access protected
     * @param string $url 跳转的URL表达式
     * @param array $params 其它URL参数
     * @param integer $delay 延时跳转的时间 单位为秒
     * @param string $msg 跳转提示信息
     * @return void
     */
    protected function redirect($url, $params = array(), $delay = 0, $msg = '')
    {
        $url = U($url, $params);
        redirect($url, $delay, $msg);
    }

    /**
     * 默认跳转操作 支持错误导向和正确跳转
     * 调用模板显示 默认为public目录下面的success页面
     * 提示页面为可配置 支持模板标签
     * @param string $message 提示信息
     * @param Boolean $status 状态
     * @param string $jumpUrl 页面跳转地址
     * @param Boolean $ajax 是否为Ajax方式
     * @access private
     * @return void
     */
    private function dispatchJump($message, $status = 1, $jumpUrl = '', $ajax = false)
    {
        // 判断是否为AJAX返回
        if ($ajax || $this->isAjax()) $this->ajaxReturn($ajax, $message, $status);
        if (!empty($jumpUrl)) $this->assign('jumpUrl', $jumpUrl);
        // 提示标题
        $this->assign('msgTitle', $status ? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_'));
        //如果设置了关闭窗口，则提示完毕后自动关闭窗口
        if ($this->get('closeWin')) $this->assign('jumpUrl', 'javascript:window.close();');
        $this->assign('status', $status);   // 状态
        //保证输出不受静态缓存影响
        C('HTML_CACHE_ON', false);
        if ($status) { //发送成功信息
            $this->assign('message', $message);// 提示信息
            // 成功操作后默认停留1秒
            if (!$this->get('waitSecond')) $this->assign('waitSecond', "1");
            // 默认操作成功自动返回操作前页面
            if (!$this->get('jumpUrl')) $this->assign("jumpUrl", $_SERVER["HTTP_REFERER"]);
            $this->display(C('TMPL_ACTION_SUCCESS'));
        } else {
            $this->assign('error', $message);// 提示信息
            //发生错误时候默认停留3秒
            if (!$this->get('waitSecond')) $this->assign('waitSecond', "3");
            // 默认发生错误的话自动返回上页
            if (!$this->get('jumpUrl')) $this->assign('jumpUrl', "javascript:history.back(-1);");
            $this->display(C('TMPL_ACTION_ERROR'));
            // 中止执行  避免出错后继续执行
            exit;
        }
    }

    /**
     * 加载模板和页面输出 可以返回输出内容
     * @access public
     * @param string $templateFile 模板文件名
     * @param string $charset 模板输出字符集
     * @param string $contentType 输出类型
     * @return mixed
     */
    public function display($templateFile = '', $charset = '', $contentType = '')
    {
        G('viewStartTime');
        // 视图开始标签
        tag('view_begin', $templateFile);
        // 解析并获取模板内容
        $content = $this->fetch($templateFile);
        // 输出模板内容
        $this->show($content, $charset, $contentType);
        // 视图结束标签
        tag('view_end');
    }

    /**
     * 输出内容文本可以包括Html
     * @access public
     * @param string $content 输出内容
     * @param string $charset 模板输出字符集
     * @param string $contentType 输出类型
     * @return mixed
     */
    public function show($content, $charset = '', $contentType = '')
    {
        if (empty($charset)) $charset = C('DEFAULT_CHARSET');
        if (empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE');
        // 网页字符编码
        header("Content-Type:" . $contentType . "; charset=" . $charset);
        header("Cache-control: private");  //支持页面回跳
        header("X-Powered-By:TOPThink/" . THINK_VERSION);
        // 输出模板文件
        echo $content;
    }

    /**
     * 解析和获取模板内容 用于输出
     * @access public
     * @param string $templateFile 模板文件名
     * @return string
     */
    public function fetch($templateFile = '')
    {
        // 模板文件解析标签
        tag('view_template', $templateFile);
        // 模板文件不存在直接返回
        if (!is_file($templateFile)) return NULL;
        // 页面缓存
        ob_start();
        ob_implicit_flush(0);
        // 视图解析标签
        $params = array('var' => $this->tVar, 'file' => $templateFile);
        $result = tag('view_parse', $params);
        if (false === $result) { // 未定义行为 则采用PHP原生模板
            // 模板阵列变量分解成为独立变量
            extract($this->tVar, EXTR_OVERWRITE);
            // 直接载入PHP模板
            include $templateFile;
        }
        // 获取并清空缓存
        $content = ob_get_clean();
        // 内容过滤标签
        tag('view_filter', $content);
        // 输出模板文件
        return $content;
    }

    /**
     * 析构方法
     * @access public
     */
    public function __destruct()
    {
        // 保存日志
        if (C('LOG_RECORD')) Log::save();
        // 执行后续操作
        tag('action_end');
    }
}